{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Introduction to Survival Support Vector Machine\n",
    "\n",
    "This guide demonstrates how to use the efficient implementation of *Survival Support Vector Machines*, which is an extension of the standard [Support Vector Machine](https://en.wikipedia.org/wiki/Support_vector_machine) to right-censored time-to-event data. Its main advantage is that it can account for complex, non-linear relationships between features and survival via the so-called kernel trick. A kernel function implicitly maps the input features into high-dimensional feature spaces where survival can be described by a hyperplane. This makes Survival Support Vector Machines extremely versatile and applicable to a wide a range of data. A popular example for such a kernel function is the [Radial Basis Function](https://en.wikipedia.org/wiki/Radial_basis_function_kernel).\n",
    "\n",
    "Survival analysis in the context of Support Vector Machines can be described in two different ways:\n",
    "\n",
    "1. As a **ranking** problem: the model learns to assign samples with shorter survival times a lower *rank* by considering all possible pairs of samples in the training data.\n",
    "2. As a **regression** problem: the model learns to directly predict the (log) survival time.\n",
    "\n",
    "In both cases, the disadvantage is that predictions cannot be easily related to standard quantities in survival analysis, namely survival function and cumulative hazard function. Moreover, they have to retain a copy of the training data to do predictions.\n",
    "\n",
    "Let's start by taking a closer look at the Linear Survival Support Vector Machine, which does not allow selecting a specific kernel function, but can be fitted faster than the more generic Kernel Survival Support Vector Machine.\n",
    "\n",
    "\n",
    "## Linear Survival Support Vector Machine\n",
    "\n",
    "The class [sksurv.svm.FastSurvivalSVM](https://scikit-survival.readthedocs.io/en/latest/api/generated/sksurv.svm.FastSurvivalSVM.html#sksurv.svm.FastSurvivalSVM) is used to train\n",
    "a linear Survival Support Vector Machine. Training data consists of $n$ triplets $(\\mathbf{x}_i, y_i, \\delta_i)$, where\n",
    "$\\mathbf{x}_i$ is a $d$-dimensional feature vector, $y_i > 0$ the survival time or time of censoring, and $\\delta_i \\in \\{0,1\\}$ the binary event indicator. Using the training data, the objective is to minimize the following function:\n",
    "\n",
    "\\begin{equation}\n",
    "\\arg \\min_{\\mathbf{w}, b} \\frac{1}{2} \\mathbf{w}^T \\mathbf{w}+ \\frac{\\alpha}{2} \\left[\n",
    "r \\sum_{i,j \\in \\mathcal{P}}\n",
    "\\max(0, 1 - (\\mathbf{w}^T \\mathbf{x}_i - \\mathbf{w}^T \\mathbf{x}_j))^2\n",
    "+ (1 - r) \\sum_{i=0}^n \\left( \\zeta_{\\mathbf{w},b} (y_i, x_i, \\delta_i) \\right)^2\n",
    "\\right]\n",
    "\\end{equation}\n",
    "\n",
    "\\begin{equation}\n",
    "\\zeta_{\\mathbf{w},b} (y_i, \\mathbf{x}_i, \\delta_i) =\n",
    "\\begin{cases}\n",
    "\\max(0, y_i - \\mathbf{w}^T \\mathbf{x}_i - b) & \\text{if $\\delta_i = 0$,}\\\\\n",
    "y_i - \\mathbf{w}^T \\mathbf{x}_i - b & \\text{if $\\delta_i = 1$,}\\\\\n",
    "\\end{cases}\n",
    "\\end{equation}\n",
    "\n",
    "\\begin{equation}\n",
    "\\mathcal{P} = \\{ (i, j)~|~y_i > y_j \\land \\delta_j = 1 \\}_{i,j=1,\\dots,n}\n",
    "\\end{equation}\n",
    "\n",
    "The hyper-parameter $\\alpha > 0$ determines the amount of regularization to apply: a smaller value increases the amount of regularization and a higher value reduces the amount of regularization. The hyper-parameter $r \\in [0; 1]$ determines the trade-off between the ranking objective and the regression objective. If $r = 1$ it reduces to the ranking objective, and if $r = 0$ to the regression objective.\n",
    "\n",
    "The class [sksurv.svm.FastSurvivalSVM](https://scikit-survival.readthedocs.io/en/latest/api/generated/sksurv.svm.FastSurvivalSVM.html#sksurv.svm.FastSurvivalSVM) adheres to interfaces used in [scikit-learn](https://scikit-learn.org) and thus it is possible to combine it with auxiliary classes and functions from scikit-learn. In this example, we are going to use the ranking objective ($r = 1$) and [GridSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html) to determine the best setting for the hyper-parameter $\\alpha$ on the Veteran's Lung Cancer data. \n",
    "\n",
    "First, we have to import the classes we are going to use."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import pandas\n",
    "import seaborn as sns\n",
    "from sklearn import set_config\n",
    "from sklearn.model_selection import GridSearchCV, ShuffleSplit\n",
    "\n",
    "from sksurv.column import encode_categorical\n",
    "from sksurv.datasets import load_veterans_lung_cancer\n",
    "from sksurv.metrics import concordance_index_censored\n",
    "from sksurv.svm import FastSurvivalSVM\n",
    "\n",
    "set_config(display=\"text\")  # displays text representation of estimators\n",
    "sns.set_style(\"whitegrid\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we load data of the *Veteran's Administration Lung Cancer Trial* from disk and convert it to numeric values. The data consists of 137 patients and 6 features. The primary outcome measure is death (`Status`, `Survival_in_days`).\n",
    "The original data can be retrieved from http://lib.stat.cmu.edu/datasets/veteran."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "data_x, y = load_veterans_lung_cancer()\n",
    "x = encode_categorical(data_x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`data_x` is a data frame containing the features, and `y` is a structured array containing the event indicator $\\delta_i$, as boolean, and the survival/censoring time $y_i$ for training.\n",
    "\n",
    "Now, we are essentially ready to start training, but before let's determine what the amount of censoring for this data is and plot the survival/censoring times."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6.6% of records are censored\n"
     ]
    }
   ],
   "source": [
    "n_censored = y.shape[0] - y[\"Status\"].sum()\n",
    "print(f\"{n_censored / y.shape[0] * 100:.1f}% of records are censored\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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IGLewcOsg4t5B08gZ327YGkyLB577DH97Gc/04wZM1RTU6PFixerf//+WrJkiV588UUlJCQoJSXFfMEAACD0NBkWnTt31urVq2+5vbCwMCALAgAAoYs3nwAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABmOnRY1NTWtenxAADcbTxtvYC25Alzq2/mmy0+/uTKCYarAQAg9HXoMxYAAMAWYQEAAMw0+lKI3+/X4sWLdebMGV2/fl1paWm67777lJmZKZfLpQEDBig7O1tuN30CAACaCIs//vGP6tq1q1atWqUrV67oiSee0MCBA5Wenq6kpCQtXbpUxcXFevTRR4O1XgAA0I41eqph7Nixevrpp+s/DgsLU1lZmRITEyVJycnJ2rt3b2BXCAAAQkajZyyioqIkSVVVVVqwYIHS09OVn58vl8tV//nKysomn8Tn86m8vNxgubcaNGhQQB73TgXq62qPvF5vh/p62xrzDh5mHVzMO3jaYtZNXm569uxZzZs3T9OnT9ekSZO0atWq+s9VV1crNja2ySeJiIho8wAIlLv162pIeXl5h/p62xrzDh5mHVzMO3gCOevbBUujL4VcunRJs2fP1qJFizR58mRJ0uDBg1VaWipJKikp0ahRo4yXCgAAQlWjYfHrX/9an376qdauXavU1FSlpqYqPT1dBQUFmjJlivx+v1JSUoK1VgAA0M41+lJIVlaWsrKybrm9sLAwYAsCAAChizegAAAAZggLAABghrAAAABmCAsAAGCGsAAAAGYICwAAYIawAAAAZggLAABghrAAAABm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",
      "text/plain": [
       "<Figure size 648x432 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(9, 6))\n",
    "val, bins, patches = plt.hist(\n",
    "    (y[\"Survival_in_days\"][y[\"Status\"]], y[\"Survival_in_days\"][~y[\"Status\"]]), bins=30, stacked=True\n",
    ")\n",
    "_ = plt.legend(patches, [\"Time of Death\", \"Time of Censoring\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we need to create an initial model with default parameters that is subsequently used in the grid search."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "estimator = FastSurvivalSVM(max_iter=1000, tol=1e-5, random_state=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we define a function for evaluating the performance of models during grid search. We use Harrell's concordance index."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def score_survival_model(model, X, y):\n",
    "    prediction = model.predict(X)\n",
    "    result = concordance_index_censored(y[\"Status\"], y[\"Survival_in_days\"], prediction)\n",
    "    return result[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The last part of the setup specifies the set of parameters we want to try and how many repetitions of training and testing we want to perform for each parameter setting. In the end, the parameters that on average performed best across all test sets (100 in this case) are selected. [GridSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html) can leverage multiple cores by evaluating multiple parameter settings concurrently (4 jobs in this example)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "param_grid = {\"alpha\": [2.0**v for v in range(-12, 13, 2)]}\n",
    "cv = ShuffleSplit(n_splits=100, test_size=0.5, random_state=0)\n",
    "gcv = GridSearchCV(estimator, param_grid, scoring=score_survival_model, n_jobs=1, refit=False, cv=cv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, start the hyper-parameter search. This can take a while since a total of ``13 * 100 = 1300`` fits have to be evaluated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import warnings\n",
    "\n",
    "warnings.filterwarnings(\"ignore\", category=UserWarning)\n",
    "gcv = gcv.fit(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's check what is the best average performance across 100 random train/test splits we got and the corresponding hyper-parameters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('0.720', {'alpha': 0.00390625})"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f\"{gcv.best_score_:.3f}\", gcv.best_params_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we retrieve all 100 test scores for each parameter setting and visualize their distribution by box plots."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_performance(gcv):\n",
    "    n_splits = gcv.cv.n_splits\n",
    "    cv_scores = {\"alpha\": [], \"test_score\": [], \"split\": []}\n",
    "    order = []\n",
    "    for i, params in enumerate(gcv.cv_results_[\"params\"]):\n",
    "        name = f'{params[\"alpha\"]:.5f}'\n",
    "        order.append(name)\n",
    "        for j in range(n_splits):\n",
    "            vs = gcv.cv_results_[f\"split{j}_test_score\"][i]\n",
    "            cv_scores[\"alpha\"].append(name)\n",
    "            cv_scores[\"test_score\"].append(vs)\n",
    "            cv_scores[\"split\"].append(j)\n",
    "    df = pandas.DataFrame.from_dict(cv_scores)\n",
    "    _, ax = plt.subplots(figsize=(11, 6))\n",
    "    sns.boxplot(x=\"alpha\", y=\"test_score\", hue=\"alpha\", data=df, order=order, ax=ax)\n",
    "    _, xtext = plt.xticks()\n",
    "    for t in xtext:\n",
    "        t.set_rotation(\"vertical\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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oKDAeu+996whQ4Y4Hc0n07f99OnTrbvuusuaP3++tWzZMmv+/PnWXXfdZU2bNs3paKd0su3r8Xisfv36OZCmepKTk63vvvuu3LSDBw8akd2yLOuhhx6yXn75ZSs3N9c6cOCAlZuba7388svW8OHDnY7mU2UdwInvK4fRJbVq1UrPPvusxo4dq65duyooKMjpSNVy1llnaerUqXK73SouLtabb76pyMhI1atXz+loPvXo0UOff/65jh49qp49ezodp1oiIiK0YMECJScnq1GjRpo6daoefPDBCqdlBKKYmBjNmDFDV199tSIjI717qBo1auR0NJ9Mzi5JbrdbvXr18j6OjIzUDTfcoDfeeMPBVFVj+rb/9NNPtXDhwnLTXC6XBgwYENB7CEtLS/Xtt9/q/PPP90779ttvFRwc+MMuSktLdc4555Sbds455xjze/bHH3/Uc889V27ahRdeqEGDBjmUqOrCw8P1zjvvKDExUfXr15fb7dbatWsd6QYcRv+d6dOna+XKlfroo4+cjlJlbrdbb731luLj4xUVFaWZM2eqQYMGuv/++9W4cWOn49Vabrdbr7/+um6//XZFRkZKkr788ks999xzeumllxxOd2plh4Y2bdrkPZSbkJCg5OTkgD809NvshYWFioyMVMeOHTVw4MCAzy5J999/v+Lj4ysUtj179uiFF15wOt4pmb7tBwwYoOeee65cafvmm2/08MMPa8mSJQ4mO7WcnBylpaWppKREkZGRcrvdCgsL01NPPWXEKQAbN27UlVdeqfr163tPAejUqZPuu+8+p+P5NGzYMN10000VCtt7772nOXPmOB3vlPLz8zVz5kxt3rxZhYWFioiIUEJCglJSUvx+yg5l8992796t8PBwxcXFeadt2bJFl156qYOpqq6oqEi7du3SsWPH1LBhQ8XHxxvzl6PJ2fPz89WwYUPt379fubm5uuCCC3TBBRc4Hcsnt9vtLci7du3Szp07dfHFF6tVq1YOJ6uakpIS7dy5U263W2effbZat25txGA+yfzCZvK2N7m0Sb9+b8tKQ9n31wQ7duyo8Hm/6KKLnI5VJYFU2E5XXl6e9/vq1OAsyqakmTNnat26dSotLVW7du301FNPSZIGDx6sBQsWOJzOtzVr1ujFF19UXFycsrOzdemll+qHH37QI4884h0hHahMzj5+/Hidd955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Pn26Zs6cqbFjx+qBBx7QZZddpp07d2rcuHFasmSJX7NQNmX2ZSUks/OT3Rlkd87DDz+sMWPGaObMmcbcwaZMTEyMnn/+eT399NPaunWr03GqbfTo0XrggQc0adIk/elPf9KDDz6oDRs2KDU1Va+88orT8Sp16623avny5XriiSd01llnKTU1Vc8++6zTsapkx44dGjt2rG699Va98cYbqlevnkpLS5WUlGRE2bziiisUHh6uunXryrIsHTlyRNddd52CgoK0atUqp+OdUlhYmJo0aSJJuuyyyyRJF154oSNZGI0u80compyf7M4gu7PmzJmjuLi4CgNVTPLWW2/prbfeqnDB7kBWtif29ttv1+uvv+6dPnDgQC1atMjBZL7l5ubqueee02OPPaa0tDRjbs2alJSkl19+WRkZGRo1apSio6P1008/6Y477tBbb73ldDyf9u7dqylTpmjkyJFq06aNUXvzJ02apBMnTqhJkybav3+/unXrpk8++UQej0fp6el+zULZBACcEYYPH66bb75ZP/zwg6Kiory/fN955x3NnTvX6Xg+/fTTT3r88ce1f/9+vf/++07HqZJPPvlEU6dOVXx8vP71r3+pffv22rNnj0aOHKlevXo5Ha9K3G63xo4dq65du2rZsmXGFH2Px6N3331X69atU35+vqKiotSpUyf179/f76cAUDYBAGeEvLw8PfPMM9q8ebMOHjzo/eU7evRonXvuuU7Hq9Ty5cv1/fffq1u3bho5cqT3Uk3jxo3TFVdc4XQ8nwoLC5Wdna38/Hw1bNhQ7dq1U3R0tNOxqm369OlauXKlPvroI6ejVFlRUZF27typ48ePq2HDhoqPj3fkCBBlEwCAANa3b19lZmYqJSVFaWlpatGihQ4dOqThw4dr+fLlTsc7pQ8++EA9e/ZUYWGhZsyYoZ07d+qiiy5SSkqKIiIinI5XJbt371Z4eLji4uK807Zs2VJhoGKgWbNmjV588UXFxcUpJydHl1xyiX744Qc98sgj5W4f6g8MEAIAnBFOdiWAMoE8qrtOnTqqV6+eIiIi1LRpU0lSkyZNjDhHedGiRerZs6cmT56s888/X2PGjNFnn32msWPHGjHIaebMmVq3bp1KS0vVrl07721Nn3322YA/nP7aa69p8eLFCgsLU35+vqZMmaLXXntNd999txYuXOjXLJRNAMAZwdQrAVxzzTVKSUlRfHy87rnnHiUmJuof//iH/vKXvzgdrcr27duniRMnSpJatWplzKHotWvXavHixQoKCtLTTz+ttLQ0paWlyYSDwgUFBd4/SMLDw3XgwAFFRkZWuJyTP1A2AQBnhEsvvVS9e/fWrl27jLoSwN13363PP/9c69at07nnnqujR4/K5XKpa9euTkfzad++fZo3b55CQkK0Y8cOtWvXTlu3bnWk8JyOsmvgSr9eOis1NVVz5swxYq9yr1691L9/f/35z3/Wxo0bNWjQIL366qtq166d37NwziYAALDFjh07tGPHDm3fvl2XXHKJrr32Wg0bNkyPPfaYOnbs6HQ8n+bNm6f33ntPc+bMUVRUlIqLi5WSkqKNGzd6L6wfyHbv3q29e/eqTZs2atmypfLy8hwZnEXZBAAAtli9erUmTJig0NBQPfjgg7rhhhskSYMHDw74cx7LfPPNNzr33HPLnXqRlZWla6+91sFUVZOVlaVPP/1UbrdbZ599tjp16qTrr7/e73tmOYwOAABsMXv2bL399tuyLEsPPPCAiouL1adPHyPOeSyza9cuzZs3TwUFBeUKW6B76qmn5PF4dPXVVysiIkKFhYVau3at1q1bp0mTJvk1C2UTAADYok6dOoqKipIkvfTSSxoyZIjOOeccI855lAKrsFXXnj17Ktzhq3v37kpOTvZ7FsomAACwxXnnnafJkyfrgQceUGRkpGbMmKFhw4bp559/djpalQRSYasuj8ejjRs3lrum5oYNG1SnTh2/Zwn2+xoBAMAZIT09XW3atPHuyTznnHO0YMEC9ezZ0+FkVVNW2H7LqcJWXRkZGXrttdfUpUsXJSYm6uKLL9bcuXM1YcIEv2dhgBAAAMBJHDhwQJMnT9b27dtlWZaCg4PVrl07jR49Ws2bN3c63il9/fXXkuQ9P3b06NGaMmWKJKlFixZ+zULZBAAAqGW6du2qunXrqnHjxrIsS7t27dKFF14oSX6/EgBlEwAA4CRMvcWpJB09elTjxo3TwIEDdeWVV8rlcikzM9ORLJRNAACAk9iyZUultzg977zzHEpVdaWlpXr66acVExOj9evXO1Y2GSAEAABwEr+9xel5551X7j8ThIaG6oknnvAeSncKezYBAABgG/ZsAgAAwDaUTQAAANiGsgkAfuByubR3795Kn7/yyiv9mAYA/IeyCQAAANtwb3QAqGFut1tPPPGECgoKlJ+fr/79+3ufmz59ur766isdPXpUP//8s8aMGaPOnTuruLhYqamp+u677xQVFaUXX3xRR48eVVpamoqKivTTTz9pxIgRuvbaax18ZwBQfZRNAKhh+/fv1w033KD/+q//0qFDh+RyudSkSRPv83Xr1tWCBQu0Z88epaamasWKFTp27JgeeughnX/++XK5XMrNzZXb7dbtt9+uyy+/XJs3b9b06dMpmwCMQ9kEgBoWGxur+fPn66OPPlJkZKRKS0vLPf+Xv/xFktS6dWsdOXJEktSgQQOdf/753tcfP35cjRo10qxZs7Rs2TIFBQVVWA4AmIBzNgGghs2dO1cdOnTQ1KlTdf3111e4mPL27dslSbt37/bu8QwKCqqwnBdeeEG9e/fWM888o8svv9zRizIDwOlizyYA1LBu3bopLS1NK1euVFRUlEJCQlRcXOx9Pjc3V0OGDNHx48c1YcKESpdz/fXXa9KkSXr55Zd1zjnnKD8/3x/xAaBGcQchAPCj6dOnKzY2VgMHDnQ6CgD4BYfRAQAAYBv2bAIAAMA27NkEAACAbSibAAAAsA1lEwAAALahbAIAAMA2lE0AAADYhrIJAAAA2/x/CCR/8c78FdcAAAAASUVORK5CYII=",
      "text/plain": [
       "<Figure size 792x432 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_performance(gcv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can observe that the model seems to be relative robust with respect to the choice for $\\alpha$ for this dataset. Let's fit a model using the $\\alpha$ value that performed best."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "FastSurvivalSVM(alpha=0.00390625, max_iter=1000, optimizer='avltree',\n",
       "                random_state=0, tol=1e-05)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "estimator.set_params(**gcv.best_params_)\n",
    "estimator.fit(x, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It is important to remember that only if the ranking objective is used exclusively ($r = 1$),\n",
    "that predictions denote risk scores, i.e. a higher predicted value indicates shorter survival,\n",
    "a lower value longer survival."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[-1.59  -1.687]\n",
      "[( True,  72.) ( True, 411.)]\n"
     ]
    }
   ],
   "source": [
    "pred = estimator.predict(x.iloc[:2])\n",
    "print(np.round(pred, 3))\n",
    "print(y[:2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The model predicted that the first sample has a lower risk than the second sample, which is in concordance with the actual survival times."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Regression Objective\n",
    "\n",
    "If the regression objective is used ($r < 1$), the semantics are different, because now predictions are on the time scale and lower predicted values indicate shorter survival, higher values longer survival.\n",
    "Moreover, we saw from the histogram of observed times above that the distribution is skewed, therefore\n",
    "the survival/censoring times will be log-transformed by the `FastSurvivalSVM` internally, when using a $r < 1$."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's fit a model using the regression objective ($r = 0$) and compare its performance to the ranking model from above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'0.736'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ref_estimator = FastSurvivalSVM(rank_ratio=0.0, max_iter=1000, tol=1e-5, random_state=0)\n",
    "ref_estimator.fit(x, y)\n",
    "\n",
    "cindex = concordance_index_censored(\n",
    "    y[\"Status\"],\n",
    "    y[\"Survival_in_days\"],\n",
    "    -ref_estimator.predict(x),  # flip sign to obtain risk scores\n",
    ")\n",
    "f\"{cindex[0]:.3f}\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that `concordance_index_censored` expects risk scores, therefore, we had to flip the sign of predictions.\n",
    "The resulting performance of the regression model is comparable to the of the ranking model above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[120.786 149.963]\n"
     ]
    }
   ],
   "source": [
    "pred = ref_estimator.predict(x.iloc[:2])\n",
    "print(np.round(pred, 3))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Kernel Survival Support Vector Machine\n",
    "\n",
    "The *Kernel Survival Support Vector Machine* is a generalization of the *Linear Survival Support Vector Machine* that can account for more complex relationships between features and survival time, it is implemented in [sksurv.svm.FastKernelSurvivalSVM](https://scikit-survival.readthedocs.io/en/latest/api/generated/sksurv.svm.FastKernelSurvivalSVM.html#sksurv.svm.FastKernelSurvivalSVM). The disadvantage is that the choice of kernel function and its hyper-parameters is often not straightforward and requires tuning to obtain good results. For instance, the [Radial Basis Function](https://en.wikipedia.org/wiki/Radial_basis_function_kernel) has a hyper-parameter $\\gamma$ that needs to be set: $k(x, x^\\prime) = \\exp(-\\gamma \\|x-x^\\prime \\|^2)$. There are many other [built-in kernel functions](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.pairwise.pairwise_kernels.html#sklearn.metrics.pairwise.pairwise_kernels) that can be used by passing their name as `kernel` parameter to `FastKernelSurvivalSVM`.\n",
    "\n",
    "In this example, we are going to use the clinical kernel, because it is able to distinguish between continuous, ordinal, and nominal attributes. As this is a custom kernel function, we first need to pre-compute the kernel matrix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sksurv.kernels import clinical_kernel\n",
    "from sksurv.svm import FastKernelSurvivalSVM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "kernel_matrix = clinical_kernel(data_x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As with the *Linear Survival Support Vector Machine* above, we are going to determine the optimal $\\alpha$ value  by using [GridSearchCV](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "kssvm = FastKernelSurvivalSVM(optimizer=\"rbtree\", kernel=\"precomputed\", random_state=0)\n",
    "\n",
    "kgcv = GridSearchCV(kssvm, param_grid, scoring=score_survival_model, n_jobs=1, refit=False, cv=cv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that when using a custom kernel, we do not pass the original data (`data_x`) to the fit function, but the pre-computed, square kernel matrix."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "kgcv = kgcv.fit(kernel_matrix, y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, print the best average concordance index and the corresponding parameters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "('0.709', {'alpha': 0.015625})"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "f\"{kgcv.best_score_:.3f}\", kgcv.best_params_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we visualize the distribution of test scores obtained via cross-validation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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P7366qtKSEhQcHCwnn76ac2cObPe5R3uqH379lq5cqUGDhwof39/51Gt4OBgq6M1ys7ZJcnhcGj48OHOx/7+/rrzzjv15z//2cJUjbP7+/7JJ5/o9ddfr7MsKSlJ999/v9sfTaypqdE///lPdezY0bnsn//8pzw93X+4R01Nja655po6y6655hrb/J397rvvtGzZsjrLfvvb32r06NEWJWoaX19fvfPOOxowYIDatm0rh8OhHTt2WNYNOB3fRCtWrNDWrVv14YcfWh2lSRwOh9566y2Fh4crICBAq1at0pVXXqlHH31UV199tdXxWjSHw6FXXnlFDz74oPz9/SVJX3zxhZYtW6bnn3/e4nQNO3+Kad++fc5TwtHR0UpISHDrU0xS3eyVlZXy9/dXVFSUEhMT3T67JD366KMKDw+vV+Y+//xzLV++3Op4F2X39/3+++/XsmXL6hS5r7/+Wo899pg2bdpkYbLGFRQUKD09XefOnZO/v78cDod8fHz05JNPuv3lBCtXrtTevXt16623qm3bts5LCfr06aNHHnnE6niNmjhxou6+++56Ze7999/X2rVrrY53UadPn9aqVav0j3/8Q5WVlfLz81N0dLSmTp1qyWU/lNBGHD58WL6+vgoJCXEu++yzz3TjjTdamKppqqqqdOjQIZ09e1ZXXXWVwsPDbfOvTDtnl376Qb/qqqtUVlamkpISXX/99br++uutjtUoh8PhLM6HDh3SwYMH1bNnT3Xt2tXiZE1z7tw5HTx4UA6HQ+3atVO3bt3cfhDheXYuc3Z+3+1c5M5zOBzOQnH+59cODhw4UO/z3qNHD6tjNYm7lblLderUKefPq5UDwiihDVi1apV27typmpoaRURE6Mknn5QkjRs3Tq+++qrF6Rq2fft2PffccwoJCVF+fr5uvPFGffvtt/rv//5v52htd2Xn7JK0YMECXXfddWrfvr02bNigvn376rPPPtPQoUM1ceJEq+M16Pxne8uWLXrjjTfUr18/7du3T/fdd5/i4+Otjteg7du365lnnlFoaKhzoMNXX32lWbNm6fbbb7c6XpPYscy1hPddsmeROz+Y7T8Hx7j7YLbzSkpK9Mknn6iiokJXXnmlbQaEXchdylxTXTggzM/PTw6Hw9oBYZZciWoT999/v1FbW2sYhmFkZWUZ8+fPNwzDHgOUxo4da1RVVRmG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LXN2/3mVfsp7YZH797//bYsiZ9fBbJK9B4RJ7lfmmsrdBoRRQhtQXV1d7whK7969rQlzichunccee0xz587VqlWrbHM067w2bdroiiuukJ+fnzp16iRJ6tChg9v/Mb6Ql5eX8/R1hw4dVFtba22gJrJrmbP7z6udi5xdB7NJ9h4QJrlfmWsqdxsQRgltwA033KDZs2drwIABzhkRPv74Y91www1WR2sU2a1z44036p577tGhQ4cUGxtrdZxLctttt2nq1KkKDw/Xww8/rAEDBuhvf/ubbr75ZqujNaqiokIjRozQ2bNntXnzZv3hD39QVlZWvan13JVdy5zdf17tXOTsOphNsveAMMn9ylxTuduAMK4JbYBhGMrNza134XRsbKzb/6CQHb/U3//+d+3cuVOnT59WQECA+vTpo5iYGKtjNUl1dbUOHjyoyy67TKGhodqyZYvi4uLk7e3+/96eP3++qqur65U5K0euNoXdf15Hjx6tWbNm1Styzz33nLKzsy1M1jg7D2az+4Awu0736m4DwiihjTh58qQ+/fRT54wIvXv31tVXX211rCYhu3VOnjypvXv3Oqd7tVP+8+/9+evj7JR927Zt8vX1rXP9am5uri1O79m5zNn559XORe5CdhrMdp6dB4S5W5m7FO40IIwS2oDNmzdr06ZN6tu3r/PC6b1792rUqFFKTEy0Ol6DyG6d8/n79OnjvFbo008/VVxcnNvnt/N7n56eroqKCtXU1OiHH37QypUr5ePjY4spR8+zY5mz82fmP9mtyNl1MNt5dh7ZL7lXmWsqtxsQZuCi4uPjjerq6jrLqqqqjBEjRliUqOnIbh0757dz9oSEBOfXr776qjF16lTDMAxj7NixVkW6JG+++aYxcuRIIzMz01i+fLmRkZFhjBgxwnj99detjtYgO39mDMMwysvLjalTpxoDBw40Bg8ebAwaNMiYPHmy8dVXX1kdrVFJSUlGQUFBnWX5+flGfHy8RYmaLj093Zg3b56Rm5tr7N6928jNzTXmzZtnzJkzx+poTbJt2zbjrrvuMh555BEjJSXFmD59ujFs2DDjf/7nf6yO1qD4+HijoqKizrIzZ85Y9vPq/hdKWaimpkZVVVV1LvL+97//bYt/pZHdOnbOb+fsP/74o6qrq+Xj46OkpCR98803WrRokdWxmmzLli1644036rz31dXV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",
      "text/plain": [
       "<Figure size 792x432 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_performance(kgcv)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can see that the choice of $\\alpha$ is much more important here, compared to the Linear Survival Support Vector Machine. Nevertheless, the best performance is below that of the linear model, which illustrates that choosing a good kernel function is essential, but also a non-trivial task."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## References\n",
    "\n",
    "> Pölsterl, S., Navab, N., and Katouzian, A.,\n",
    "> *Fast Training of Support Vector Machines for Survival Analysis*,\n",
    "> Machine Learning and Knowledge Discovery in Databases: European Conference,\n",
    "> ECML PKDD 2015, Porto, Portugal,\n",
    "> Lecture Notes in Computer Science, vol. 9285, pp. 243-259 (2015)\n",
    "\n",
    "> Pölsterl, S., Navab, N., and Katouzian, A.,\n",
    "> *An Efficient Training Algorithm for Kernel Survival Support Vector Machines*\n",
    "> 4th Workshop on Machine Learning in Life Sciences,\n",
    "> 23 September 2016, Riva del Garda, Italy"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
